/*
 * @description: 请求封装
 * @Author: Jay
 * @Date: 2022-06-08 11:41:36
 * @LastEditors: Jay
 * @LastEditTime: 2022-06-08 15:29:38
 */
// 导入axios
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";
// 使用element-ui ElMessage做消息提醒  ElLoading加载
//请求头
import { JsonResult } from "~/api/types";
import { ElLoading, ElMessage, ElMessageBox, IElMessageBox } from "element-plus";
import { LoadingInstance } from "element-plus/es/components/loading/src/loading";
import router from "~/router";

let loadingService: LoadingInstance;

let errorBoxService: IElMessageBox = ElMessageBox;

//加载配置
let requestNum: number = 0,
  loading: boolean = true;

let errorBoxNum: number = 0,
  showErrorBox: boolean = true;

//加载动画
const addLoading = () => {
  // 防止重复弹出
  requestNum++;
  if (requestNum == 1) {
    loadingService = ElLoading.service({
      lock: true,
      text: "加载中",
      background: "rgba(0,0,0,0.6)",
    });
  }
};

// 关闭 加载动画
const cancelLoading = () => {
  requestNum--;
  // 关闭 加载动画
  if (requestNum === 0) {
    requestAnimationFrame(() => {
      setTimeout(() => {
        loadingService.close();
      }, 300);
    });
  }
};

function showMessageBox(status: number, msg?: string) {
  errorBoxNum++;
  if (errorBoxNum == 1) {
    const href = window.location.href;
    if (status === 401 && !href.endsWith("/#/login")) {
      errorBoxService.confirm(
        "您的授权已过期，请重新登录！",
        "未授权！",
        {
          confirmButtonText: "重新登录",
          showCancelButton: false,
          showClose: false,
          type: "error",
        },
      ).then(async () => {
        window.localStorage.removeItem("token");
        await router.push("/login");
        cancelMessageBox();
      });
    }
  }
}

function cancelMessageBox() {
  errorBoxNum--;
  // 关闭 加载动画
  if (errorBoxNum === 0) {
    errorBoxService.close();
  }
}

// @ts-ignore
export interface IceAxiosInstance extends AxiosInstance {
  get<T = any, R = AxiosResponse<T>, D = any>(url: string, config?: AxiosRequestConfig<D>): Promise<JsonResult<T>>;

  post<T = any, R = AxiosResponse<T>, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>): Promise<JsonResult<T>>;
}

//请求配置
export const createAxios = <T>(
  config?: AxiosRequestConfig,
): IceAxiosInstance => {
  const instance: AxiosInstance = axios.create({
    baseURL: "/api",
    //超时配置
    timeout: 60 * 1000,
    ...config,
  });

  // 添加请求拦截器
  instance.interceptors.request.use(
    function(config: any) {
      const token = localStorage.getItem("token");

      if (token) {
        config.headers["Authorization"] = "Bearer " + token;
      }
      //加载动画
      if (loading) addLoading();
      return config;
    },
    function(error) {
      // 请求错误
      return Promise.reject(error);
    },
  );

  // 添加响应拦截器

  instance.interceptors.response.use(
    (response: AxiosResponse) => {
      // 关闭加载 动画
      if (loading) cancelLoading();
      //返回参数

      const JsonResult: JsonResult<any> = response.data;
      if (JsonResult.code && JsonResult.code != 0) {
        ElMessage.error(JsonResult.msg);
      }
      return response.data;
    },
    async function(error) {
      // 关闭加载 动画
      if (loading) cancelLoading();
      /***** 接收到异常响应的处理开始 *****/
      if (error && error.response) {
        // 1.公共错误处理
        // 2.根据响应码具体处理
        switch (error.response.status) {
          case 400:
            error.message = "错误请求";
            break;
          case 401:
            error.message = "未授权，请重新登录";
            showMessageBox(error.response.status);
            return;
          case 403:
            error.message = "拒绝访问";
            break;
          case 404:
            error.message = "请求错误,未找到该资源";
            break;
          case 405:
            error.message = "请求方法未允许";
            break;
          case 408:
            error.message = "请求超时";
            break;
          case 500:
            error.message = "服务器端异常";
            break;
          case 501:
            error.message = "网络未实现";
            break;
          case 502:
            error.message = "网络错误";
            break;
          case 503:
            error.message = "服务不可用";
            break;
          case 504:
            error.message = "网络超时";
            break;
          case 505:
            error.message = "http版本不支持该请求";
            break;
          default:
            error.message = `连接错误${error.response.status}`;
        }
        //提示
        ElMessage.error(error.message);
      } else {
        // 超时处理
        if (JSON.stringify(error).includes("timeout")) {
          error.message = "服务器响应超时，请刷新当前页";
        } else {
          error.message = "连接服务器失败";
        }
      }
      /***** 处理结束 *****/
      return Promise.resolve(error.response);
    },
  );

  return instance;
};
